/**
 * @author 14544
 * @date 2020/3/30 10:54
 */

// 内置的 URL 类为创建和解析 URL 提供了非常方便的接口。
// 没有一个网络方法一定要使用 URL 对象，因为只使用字符串就已经足够了。因此从技术上来讲我们没有必要使用 URL。但是有些时候 URL 对象真的很有用。

// 使用方法 url = new URL(url, [base]) 注意： IE下不兼容 ，IE10及以上只有URL的静态方法：createObjectURL、revokeObjectURL

// url  是一个表示绝对或相对 URL 的 DOMString。如果url 是相对 URL，则会将 base 用作基准 URL。如果 url 是绝对URL，则将忽略 base，无论是否有给出。
// base 可选 是一个表示基准 URL 的 DOMString，在 url 是相对 URL 时，它才会起效。如果未指定，则默认为 ''。
{
    // 我们可以在 fetch 或者 XMLHttpRequest 中使用 URL 对象，几乎在任何能使用字符串 URL 的地方都能使用 URL 对象。
    // 在绝大多数方法中，它会自动转换为字符串。
    const url = new URL('/gov/gov.do?name=wm&age=22', 'https://192.168.200.124');

    // 使用searchParams 可以自动的为参数进行编码 （encodeURI 的编码形式，只是按照的是最新的标准）
    url.searchParams.set('width', '222');
    url.searchParams.set('height', '333');

    console.log(url, url.searchParams.get('name'), url.searchParams.get('height'))
}

// URL.createObjectURL() 静态方法会创建一个 DOMString，表示参数对象的URL。
// 这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。

{
    // let blobUrl = URL.createObjectURL(blob)

    //在每次调用 createObjectURL() 方法时，都会创建一个新的 URL 对象，即使你已经用相同的对象作为参数创建过。
    // 当不再需要这些 URL 对象时，每个对象必须通过调用 URL.revokeObjectURL() 方法来释放。

    // URL.revokeObjectURL(blobUrl)

    // 浏览器在 document 卸载的时候，会自动释放它们，但是为了获得最佳性能和内存使用状况，你应该在安全的时机主动释放掉它们。
}

//  URL.createObjectURL() 、URL.revokeObjectURL 的完整实例
{
    // 创建 <img> 元素
    let img = document.createElement('img');
    img.style = 'position:fixed;top:10px;left:10px;width:100px';
    document.body.append(img);

    fetch('/webpic/W0201905/W020190507/W020190507402699829108_600.jpeg')
        .then(res => res.blob()) // 以 Blob 对象下载
        .then(blob => {
            img.src = URL.createObjectURL(blob); // 显示图片
            console.log(img.src,blob)

            setTimeout(() => {
                URL.revokeObjectURL(img.src); //  3 秒后 释放资源。防止内存泄漏
            }, 3000);
        });
}


// 使用旧API手动编码字符串

// encodeURL 与 encodeURIComponent 的异同
// 共同点：都是对统一资源标识符（URI）的组成部分进行编码的方法。它使用一到四个转义序列来表示字符串中的每个字符的UTF-8编码
{
    // 在 URL 路径中使用 cyrcillic ( 非拉丁字母和空格) 字符

    let url1 = encodeURI('http://site.com/привет');
    let url2 = encodeURIComponent('http://site.com/привет');

    // 每个 cyrillic 都被以两个 %xx 的形式编码
    // 它们一起组成了字符的 UTF-8 代码
    console.log(url1, url2); // 我们可以发现使用不同的编码方法，返回的编码后的字符串也不尽相同
}
// 不同点：对编码字符的选择不完全相同
{
    var set1 = ";,/?:@&=+$";  // 保留字符
    var set2 = "-_.!~*'()";   // 不转义字符
    var set3 = "#";           // 数字标志
    var set4 = "ABC abc 123"; // 字母数字字符和空格

    console.log(encodeURI(set1)); // ;,/?:@&=+$
    console.log(encodeURI(set2)); // -_.!~*'()
    console.log(encodeURI(set3)); // #
    console.log(encodeURI(set4)); // ABC%20abc%20123 (the space gets encoded as %20)

    console.log(encodeURIComponent(set1)); // %3B%2C%2F%3F%3A%40%26%3D%2B%24
    console.log(encodeURIComponent(set2)); // -_.!~*'()
    console.log(encodeURIComponent(set3)); // %23
    console.log(encodeURIComponent(set4)); // ABC%20abc%20123 (the space gets encoded as %20)

    // 可以看到 set1、 set3 在encodeURL中不进行编码，而在encodeURLComponent要进行编码
    // 这就是 encodeURIComponent 所做的事情。它编码与 encodeURI 相同的字符，但又包括了许多其他字符，以使得结果值在任何 URL 组件中都可以安全使用。
}

// 使用encodeURL
{
    let search = 'name=wang&Li';
    console.log(encodeURI(`http:www.baidu.com?${search}`)) // http:www.baidu.com?name=wang&Li
    // 由于&是保留字符，没有对其进行编码，但这里我们想要把wang&li作为一个整体参数赋给name，而这里没有编码的话，浏览器会认为name=wang一个参数，加上另一个li参数
    // 从而与我们的预期不符,所以我们想要将&一并编码给name
}
// 使用encodeURLComponent
{
    let search = 'name=wang&Li';
    console.log(encodeURIComponent(`http:www.baidu.com?${search}`)) // http%3Awww.baidu.com%3Fname%3Dwang%26Li
    // 我们发现对整个url涉及到特殊字符都进行了编码，其实在url主体部分的特殊字符一般不需要编码，影响了可读性，而参数中&编码了,这里是我们想要的
}

// 使用encodeURL 和 encodeURLComponent 结合
{

    let url = 'http://www.baidu.com/привет';
    let search = 'name=wang&li';
    // encodeURL 编码URL主体部分
    url = encodeURI(url)

    // encodeURIComponent 编码URL参数部分
    search = '?' + encodeURISearch(search);


    function encodeURISearch(str) {
        const [key, value] = str.split('=');
        // 只对参数的key、value进行编码就行
        return encodeURIComponent(key) + '=' + encodeURIComponent(value)
    }

    // 输出最终编码后的字符车
    console.log(url + search) // http://www.baidu.com/%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82?name=wang%26li
    // 这样就达到了我们的要求

    // 对于 application/x-www-form-urlencoded (POST) 这种数据方式，就需要这种编码方式
    // 并且空格需要被替换成 '+'，所以通常使用 encodeURIComponent 的时候还会把 "%20" 替换为 "+"。
}

// 为什么要用 URL？
// 很多旧的代码使用这些函数，这些函数有时候很方便，不会导致错误。
// 但是在现代代码中，建议使用 URL 和 URLSearchParams 类。
// 其中一个理由是：它们都是基于最新的 URI 标准：RFC3986，而 encode* 函数是基于过时的 RFC2396 标准。
// 例如，IPv6 地址以不同方式处理：

{
    // IPv6 地址的合法 URL
    let url = 'http://[2607:f8b0:4005:802::1007]/';

    console.log(encodeURI(url)); // http://%5B2607:f8b0:4005:802::1007%5D/
    console.log(new URL(url).href); // http://[2607:f8b0:4005:802::1007]/

    // 正如所见，encodeURI 取代了方括号 [...]，这是不正确的，原因是：在 RFC2396 (August 1998) 时代 IPv6 URL 还不存在。
    // 这种情况很少见，encode* 函数大部分情况下都能正常使用，这只是偏好使用新 API 的其中一个原因。
}

// new URL().searchParams 就是 URLSearchParams 类的一个实例，拥有其所有的方法，IE下不兼容
{
    // 使用new URL 可以自动的为参数进行编码 （encodeURI 的编码形式，只是按照的是最新的标准）
    // 所以想要对参数进行encodeURIComponent 编码，可以单独的进行如： params.set('foo',encodeURIComponent(params.get('foo')))
    var url = new URL('https://example.com?foo=1&bar=2');

    var url2 = new URL(window.location);

    var params = new URLSearchParams(url.search);   // 传入?字符开始参数字符串

    var params3 = new URLSearchParams([["foo", 1],["bar", 2]]);  // 可以是二维数组，类似于Map结构，对应key-value

    var params4 = new URLSearchParams({"name" : 'wm' , "name" : 'zhao'}); // 传入一个对象

    console.log(url,url2)
    console.log(params.get('foo'),params3.get('bar'),params4.getAll('name'))
}